from pandac.PandaModules import *                       # Basic Panda modules
from direct.showbase.DirectObject import DirectObject   # For event handling
from direct.actor.Actor import Actor                    # For animated models
from direct.interval.IntervalGlobal import *            # For compound intervals
from direct.task import Task                            # For update functions
from direct.particles.ParticleEffect import ParticleEffect  #For particles

from direct.task import Task
import math

class Player(object):
    def __init__(self):
        #turn off default mouse control, otherwise camera isn't repositionable
        #base.disableMouse()
        self.position = [0, 0, 6]
        self.rotation = [0, 0, 0]
        self.loadModel()
        self.setUpCamera()

        self.keyMap = {"left":0, "right":0, "forward":0, "backward":0}
        taskMgr.add(self.mouseUpdate, "mouse-task")
        taskMgr.add(self.moveUpdate, "move-task")
        taskMgr.add(self.animate, "animate-task")
        self.prevtime = 0
        self.animtime = 0
        self.isMoving = False
        
        self.health = 100.0
        self.speed = 30.0
        
        self.extinguisher_mode = True
        self.melee_mode = False
        self.acting = False
        self.spraying = False
        self.has_struck = False
        self.can_strike = False
        
        self.swing_angle = 0.0
        self.swing_speed = 350.0
        
        
    def setKey(self, key, value):
        self.keyMap[key] = value
        
    def loadModel(self):
        """ make the nodepath for player """
        self.node = loader.loadModel("Art/models/Player")
        self.node.reparentTo(render)
        
        self.view = loader.loadModel("Art/models/Player")
        self.view.reparentTo(self.node)
        self.view.setPos(0,0,6)
        
        #setup Fire extinguisher model
        self.extinguisher = loader.loadModel("Art/models/Fire Extinguisher Use")
        self.extinguisher.reparentTo(self.view)
        self.extinguisher.setHpr(-90,0,15)
        self.extinguisher.setPos(0.8, 3.5, -4)
        self.extinguisher.show()
        
        #Setup axe model
        self.axe = loader.loadModel("Art/models/Axe")
        self.axe.reparentTo(self.view)
        self.axe.setHpr(-45, -50, 45)
        self.axe.setPos(-2.9, 3.5, -2.2)
        self.axe.hide()
        
        #TODO: Change to a final model or work out particle effects, 
        self.spray = ParticleEffect()
        self.spray.loadConfig("Art/models/Fire Extinguisher.ptf")   
        self.spray.setHpr(15, -105, 0)
        self.spray.setPos(.7, 5.7, -.7)
        self.spray.disable()

        
    def setUpCamera(self):
        """ puts camera at the players node """
        pl =  base.cam.node().getLens()
        pl.setFov(60)
        base.cam.node().setLens(pl)
        base.camera.reparentTo(self.view)

    def mouseUpdate(self,task):
        """ this task updates the mouse """
        md = base.win.getPointer(0)
        x = md.getX()
        y = md.getY()
        if base.win.movePointer(0, base.win.getXSize()/2, base.win.getYSize()/2):
            self.view.setH(self.view.getH() -  (x - base.win.getXSize()/2)*0.1)
            self.view.setP(self.view.getP() - (y - base.win.getYSize()/2)*0.1)
            if self.view.getP() > 90:
                self.view.setP(90)
            if self.view.getP() < -90:
                self.view.setP(-90)
            
        return task.cont

    def moveUpdate(self, task):
        elapsed = task.time - self.prevtime
        self.rotation = self.view.getHpr()
        self.position = list(self.node.getPos())
        self.vel_vec = [0, 0]
        self.angle = 0
        self.moving = False

        
        if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"] or self.keyMap["backward"]:

            if self.keyMap["forward"]:
                self.moving = True
                self.angle += 90
                if self.keyMap["left"]:
                    self.angle += 45
                if self.keyMap["right"]:
                    self.angle -= 45
            if self.keyMap["backward"]:
                self.moving = True
                self.angle -= 90
                if self.keyMap["left"]:
                    self.angle -= 45
                if self.keyMap["right"]:
                    self.angle += 45
                    
            if self.moving == False:
                if self.keyMap["left"]:
                    self.moving = True
                    self.angle = 180
                if self.keyMap["right"]:
                    self.moving = not self.moving
 
            
        if(self.moving):
            self.vel_vec = [self.speed*elapsed*math.cos(math.radians(self.rotation[0]+self.angle)),
                            self.speed*elapsed*math.sin(math.radians(self.rotation[0]+self.angle))]

        self.position[0] += self.vel_vec[0]
        self.position[1] += self.vel_vec[1]
        self.position[2] -= 15*elapsed
        
        if(self.position[2] < 0):
            self.position[2] = 0
            
        self.node.setPos(self.position[0], self.position[1], self.position[2])
        
        self.prevtime = task.time
        return Task.cont

    def sprayOn(self):
        self.spraying = True
        self.spray.start(parent = self.view, renderParent = self.view)
        #print "extinguishering!"

    def sprayOff(self):
        self.spray.disable()
        self.spraying = False
        
    def melee(self):
        '''setup axe swing'''
        self.acting = True
        
        #TODO: adjust starting angle
        #the axe needs a new rotational axis
        self.axe.setHpr(-70, -20, 0)
        self.axe.setPos(0, 2, -3)
            
    def endMelee(self):
        '''end melee animation and reset to idle'''
        self.acting = False
        self.has_struck = False
        self.can_strike = False
        self.swing_angle = 0.0
        self.axe.setHpr(-45, -50, 45)
        self.axe.setPos(-2.9, 3.5, -2.2)
    
    def animate(self, task):
        '''animate swinging axe'''
        elapsed = task.time - self.animtime
        if(self.melee_mode and self.acting):
            
            #animate downward swing
            if(self.swing_angle >= -130):
                self.swing_angle -= 1*self.swing_speed*elapsed
                self.axe.setR(self.swing_angle)
                
                #damage door halfway through swing
                if(not self.has_struck and self.swing_angle >= (-130/2)):
                    self.can_strike = True
            
            #end swing animation
            else:
                self.endMelee()
                
        self.animtime = task.time
        return task.cont

    def switchMode(self):
        '''call to switch between melee/spray mode'''
        self.extinguisher_mode = not self.extinguisher_mode
        self.melee_mode = not self.melee_mode
        self.axe.show() if self.melee_mode else self.axe.hide()
        self.extinguisher.show() if self.extinguisher_mode else self.extinguisher.hide()
        self.spray.disable()
        
        if(self.melee_mode):
            self.sprayCloud.setCenter(0,6,0)
        elif(self.extinguisher_mode):
            self.sprayCloud.setCenter(0,13,-1)
        
    def doAction(self):
        '''handle mouse left click'''
        if(self.extinguisher_mode):
            if(not self.acting):
                self.sprayOn()
        elif(self.melee_mode):
            if(not self.acting):
                self.melee()

    def endAction(self):
        '''handle mouse left click release'''
        if(self.extinguisher_mode):
            self.sprayOff()
            
    def setupCollisions(self, trav):
        
        #colision nodes and solids        
        self.playerGroundSphere = CollisionSphere(0,0,1.5,1.5)
        self.playerGroundCol = CollisionNode('playerSphere') 
        self.playerGroundCol.addSolid(self.playerGroundSphere) 
        self.playerGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.playerGroundColNp = self.node.attachNewNode(self.playerGroundCol)
        self.playerGroundCol.setFromCollideMask(BitMask32(0x2))
        #self.playerGroundColNp.show()

        trav.addCollider(self.playerGroundColNp, base.pusher)
        base.pusher.addCollider(self.playerGroundColNp, self.node)
        
        self.sprayCloud = CollisionSphere(0,13,-1,3)
        self.sprayCol = CollisionNode('sprayCloud')
        self.sprayCol.addSolid(self.sprayCloud) 
        self.sprayColNp = self.view.attachNewNode(self.sprayCol)
        #self.sprayColNp.show()
        
        trav.addCollider(self.sprayColNp, base.cHandler)